package com.briup.corejava.day21;

import com.briup.corejava.day11.pojo.Student;

import java.lang.reflect.*;

/**
 * 反射获取一个类型的所有信息
 * 获得构造器，产生对象
 * 获得属性，修改值
 * 获得方法，手动调用
 * 都是发生在运行时的
 */
public class Test4 {
    public static void main(String[] args) {
        // 获取Class对象（处理异常版）
        try {
            Class<?> clazz = Class.forName("com.briup.corejava.day11.pojo.Student");

            // 获取所有public的构造器
            Constructor<?>[] constructors = clazz.getDeclaredConstructors();
            for(Constructor<?> c : constructors) {
                //  名字
                System.out.println(c.getName());
                // 构造器的参数列表
                Class<?>[] parameterTypes = c.getParameterTypes();
                System.out.println("构造器的参数类型列表：");
                for (Class c1 : parameterTypes) {
                    System.out.println(c1.getSimpleName());
                }
                System.out.println("参数列表类型结束");
                // 修饰符
                System.out.println("修饰符： " + Modifier.toString(c.getModifiers()));
            }
            // 获得指定构造器，全参的那个
            Constructor<?> constructor = clazz.getConstructor(String.class, Integer.class);
            // 使用构造器创建对象，创建对象肯定要提供具体的属性值
            // 值怎么传取决于上面的构造器是几个参数
            Object o = constructor.newInstance("joker", 20);
            System.out.println("o = " + o);
            System.out.println("=======================");
            // 成员变量
            // 获取所有的成员变量
            Field[] declaredFields = clazz.getDeclaredFields();
            for(Field field : declaredFields){
                // 属性上什么比较值得拿？
                // 属性修饰符 类型 名字
                String m = Modifier.toString(field.getModifiers());
                String t = field.getType().getSimpleName();
                String n = field.getName();
                System.out.println(m+" "+t+" "+n+";");
            }
            // 获得一个指定属性，修改属性值
            Student s = (Student) o; // joker 20
            Field age = clazz.getDeclaredField("age");
            // 对修饰的私有变量，破开访问限制
            age.setAccessible(true);
            // 获取s对象的age值
            System.out.println("修改之前的age值："+age.get(s));
            // 运行时动态修改age值
            age.set(s,30);
            System.out.println("修改之后的age值："+age.get(s));

            // 获取所有的public方法
            Method[] methods = clazz.getMethods();
            for(Method m : methods){
                // 方法值得关注的点：
                // 方法的名字
                // 方法的参数列表
                // 方法的修饰符
                // 方法的返回值
            }
            // 获取指定方法，get和set方法
            Method get = clazz.getMethod("getAge");
            // 调用s对象get方法
            Object invoke = get.invoke(s);
            // 看一看getAge的返回值是多少
            System.out.println("调用get方法的age值为："+invoke);

        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }
}
